package com.nextwist.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import com.nexttwist.common.BaseException;
import com.nexttwist.common.BasicValidator;
import com.nexttwist.common.DBContants;
import com.nexttwist.pojo.User;
import com.nexttwist.pojo.UserStory;

public class UserDAO extends BaseDAO {

	CommonDAO commonDAO = new CommonDAO();
	BasicValidator basicValidator=new BasicValidator();
	private int userId;

	/**
	 * This method is used to get the userSpecific stories
	 * 
	 * @param userId
	 * @param start
	 * @param end
	 * @return List<UserStory>
	 */
	public List<UserStory> userSpecificStory(int userId, int start, int end)
			throws BaseException {
		try {
			PreparedStatement selectStatement = conn
					.prepareStatement(DBContants.GET_STORY);
			selectStatement.setInt(1, userId);
			selectStatement.setInt(2, start);
			selectStatement.setInt(3, end);
			ResultSet result = selectStatement.executeQuery();
			List<UserStory> userStoryList = new ArrayList<UserStory>();
			
			
			while (result.next()) {
				UserStory userStory = new UserStory();
				userStory.setStoryId(result.getInt(1));
				userStory.setStoryTitle(result.getString(2));
				userStory.setCreatedAt(result.getString(3));
				userStory.setUserId(userId);
				
				PreparedStatement storyLines = conn
						.prepareStatement(DBContants.GET_STORY_LINES);
				storyLines.setInt(1, result.getInt(1));
				ResultSet lineCount = storyLines.executeQuery();
				lineCount.last();
				int noofLine = lineCount.getRow();
				userStory.setNoOfLines(noofLine);

				PreparedStatement votes = conn
						.prepareStatement(DBContants.NO_OF_VOTES);
				votes.setInt(1, result.getInt(1));
				ResultSet voteCount = votes.executeQuery();
				voteCount.last();
				int noofVote = voteCount.getRow();
				userStory.setNoOfVotes(noofVote);
				userStoryList.add(userStory);
				
			}
			return userStoryList;
		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}

	}

	/**
	 * This method is used to get the list of followers
	 * 
	 * @param userId
	 * @return  List<User>
	 */
	public List<User> userFollower(int userId, int start, int end)
			throws BaseException {
		try {
			boolean isUserExists = false;
			List<User> followerUserList = new ArrayList<User>();
			PreparedStatement checkUser = conn
					.prepareStatement(DBContants.GET_USER_BY_USERID);
			checkUser.setInt(1, userId);
			ResultSet userRs = checkUser.executeQuery();
			if(userRs.next()){
				do{
					isUserExists = true;
				}while(userRs.next());
			}else{
				throw new Exception("Invalid User ID");
			}
			
			if(isUserExists){
			PreparedStatement getPrepare = conn
					.prepareStatement(DBContants.GET_LIST_OF_FOLLOWERS);
			getPrepare.setInt(1, userId);
			getPrepare.setInt(2, start);
			getPrepare.setInt(3, end);
			ResultSet rs = getPrepare.executeQuery();
			
			while (rs.next()) {
				followerUserList.add(constructUserObject(rs));
			}
			}
			return followerUserList;
		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}
	}

	/**
	 * This method is used to get the list of followings
	 * 
	 * @param userId
	 * @return List<User>
	 */
	public List<User> userFollowing(int userId, int start, int end)
			throws BaseException {
		try {
			boolean isUserExists = false;
			List<User> followingUserList = new ArrayList<User>();
			
			PreparedStatement checkUser = conn
					.prepareStatement(DBContants.GET_USER_BY_USERID);
			checkUser.setInt(1, userId);
			ResultSet userRs = checkUser.executeQuery();
			if(userRs.next()){
				do{
					isUserExists = true;
				}while(userRs.next());
			}else{
				throw new Exception("Invalid User ID");
			}
			
			if(isUserExists){
			PreparedStatement getPrepare = conn
					.prepareStatement(DBContants.GET_LIST_OF_FOLLOWINGS);
			getPrepare.setInt(1, userId);
			getPrepare.setInt(2, start);
			getPrepare.setInt(3, end);
			ResultSet rs = getPrepare.executeQuery();
			while (rs.next()) {
				followingUserList.add(constructUserObject(rs));
			}
			}
			return followingUserList;
		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}
	}

	/**
	 * This method is used to get the user details
	 * 
	 * @param userId
	 * @return User
	 */
	public User getUser(int userId) throws BaseException {
		try {
			PreparedStatement getUserInfo = conn
					.prepareStatement(DBContants.GET_USER_BY_USERID);
			getUserInfo.setInt(1, userId);
			ResultSet rs = getUserInfo.executeQuery();
			User userObj = new User();
			while (rs.next()) {
				userObj = constructUserObject(rs);
				userObj.setUserId(userId);
			}
			return userObj;
		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}

	}

	/**
	 * This methos is used to add users.
	 * 
	 * @param userObject
	 * @return boolean
	 * @throws BaseException
	 */
	public boolean userAdd(User userObject) throws BaseException {
		try {
			userId = commonDAO.getNewUserId();
			PreparedStatement prepareInsert = conn
					.prepareStatement(DBContants.ADD_USER);
			prepareInsert.setInt(1, userId);
			prepareInsert.setString(2, userObject.getFbuId());
			prepareInsert.setString(3, userObject.getTtrId());
			prepareInsert.setString(4, userObject.getLnkId());
			prepareInsert.setString(5, userObject.getUserName());
			prepareInsert.setString(6, userObject.getPassword());
			prepareInsert.setString(7, userObject.getFirstName());
			prepareInsert.setString(8, userObject.getLastName());
			prepareInsert.setString(9, userObject.getEmail());
			prepareInsert.setDate(10,
					new java.sql.Date(Long.valueOf(userObject.getDob())));
			prepareInsert.setString(11, userObject.getImagePath());
			prepareInsert.setString(12, userObject.getGender());
			//prepareInsert.setString(13, userObject.getTime());
			prepareInsert.setString(13, userObject.getIsAdmin() ? "Y" : "N");
			prepareInsert.setString(14, userObject.getEmailVarification());
			prepareInsert.executeUpdate();
		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}
		// TODO : have to confirm the return type of the method
		return true;
	}

	/**
	 * This method is used to update user
	 * 
	 * @param userObject
	 * @return User
	 */
	public User userUpdate(User userObject) throws BaseException {
		
		try {
			int userId = userObject.getUserId();
			PreparedStatement checkUser = conn
					.prepareStatement(DBContants.GET_USER_BY_USERID);
			checkUser.setInt(1, userId);
			ResultSet rs = checkUser.executeQuery();

			if (rs.next()) {
				do {
					PreparedStatement updateStatus = conn
							.prepareStatement(DBContants.UPDATE_USER_DELETE_FLAG);
					updateStatus.setInt(1, userId);
					int checkUpdate = updateStatus.executeUpdate();
					if (checkUpdate > 0) {
						PreparedStatement prepareInsert = conn
								.prepareStatement(DBContants.ADD_USER);
						prepareInsert.setInt(1, userId);
						prepareInsert.setString(2, userObject.getFbuId());
						prepareInsert.setString(3, userObject.getTtrId());
						prepareInsert.setString(4, userObject.getLnkId());
						prepareInsert.setString(5, userObject.getUserName());
						prepareInsert.setString(6, rs.getString("pwd"));
						prepareInsert.setString(7, userObject.getFirstName());
						prepareInsert.setString(8, userObject.getLastName());
						prepareInsert.setString(9, userObject.getEmail());
						prepareInsert.setDate(10, rs.getDate("DOB"));
						prepareInsert.setString(11, userObject.getImagePath());
						prepareInsert.setString(12, rs.getString("gender"));
						prepareInsert.setString(13, rs.getString("Isadmin"));
						prepareInsert.setString(14,
								userObject.getEmailVarification());
						prepareInsert.executeUpdate();
					}
				} while (rs.next());
			} else {
				throw new Exception("Invalid UserId");
			}

			return userObject;

		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}

	}

	/**
	 * This method is used to follow friend
	 * 
	 * @param followerId
	 * @param followingId
	 * @return String
	 */
	public String followUser(int followerId, int followingId)
			throws BaseException {
		try {
			String ret = null;
			PreparedStatement checkFriend = conn
					.prepareStatement(DBContants.GET_FOLLOWME_DETAILS);
			checkFriend.setInt(1, followerId);
			checkFriend.setInt(2, followingId);
			ResultSet rs = checkFriend.executeQuery();
			rs.last();
			if (rs.getRow() > 1) {
				ret = "Request has already been sent.";
			} else {
				PreparedStatement insertFriend = conn
						.prepareStatement(DBContants.ADD_FOLLOWME);
				insertFriend.setInt(1, followerId);
				insertFriend.setInt(2, followingId);
				insertFriend.executeUpdate();
				ret = "Request has been send successfully";
			}
			return ret;
		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}
	}

	/**
	 * this method is used to change password
	 * 
	 * @param userId
	 * @param oldPass
	 * @param newPass
	 * @return
	 */
	public String changePassword(int userId, String oldPass, String newPass)
			throws BaseException {
		try {
			PreparedStatement checkUser = conn
					.prepareStatement(DBContants.GET_USER_BY_USERID_AND_PASSWORD);
			checkUser.setInt(1, userId);
			checkUser.setString(2, oldPass);
			ResultSet rs = checkUser.executeQuery();
			if (rs.next()) {
				do {
					PreparedStatement updateStatus = conn
							.prepareStatement(DBContants.UPDATE_USER_DELETE_FLAG);
					updateStatus.setInt(1, userId);
					Integer checkUpdate = updateStatus.executeUpdate();
					if (checkUpdate > 0) {
						PreparedStatement prepareInsert = conn
								.prepareStatement(DBContants.ADD_USER);
						prepareInsert.setInt(1, userId);
						prepareInsert.setString(2, rs.getString("fbuid"));
						prepareInsert.setString(3, rs.getString("ttrid"));
						prepareInsert.setString(4, rs.getString("lnkid"));
						prepareInsert.setString(5, rs.getString("username"));
						prepareInsert.setString(6, newPass);
						prepareInsert.setString(7, rs.getString("fname"));
						prepareInsert.setString(8, rs.getString("lname"));
						prepareInsert.setString(9, rs.getString("email"));
						prepareInsert.setDate(10, rs.getDate("DOB"));
						prepareInsert.setString(11,
								rs.getString("profile image path"));
						prepareInsert.setString(12, rs.getString("gender"));
						prepareInsert.setString(13, rs.getString("time"));
						prepareInsert.setString(14, rs.getString("Isadmin"));
						prepareInsert.setString(15,
								rs.getString("email varification"));
						prepareInsert.executeUpdate();
					}
				} while (rs.next());
			} else {
				throw new Exception("Invalid UserId or Password");
			}

			// TODO: send proper email
			// commonDAO.sendMail();

			return "Password change successfully";

		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}
	}

	/**
	 * This method is used to login
	 * 
	 * @param emailId
	 * @param password
	 * @return User Object
	 */
	// TODO: need to handle the exceptions
	public UUID loginUser(String emailId, String password) throws BaseException {
		try {
			if(!basicValidator.isValidEmail(emailId))
				throw new Exception("Invalid Email ID");
			PreparedStatement getUserInfo = conn
					.prepareStatement(DBContants.USER_LOGIN);
			getUserInfo.setString(1, emailId);
			getUserInfo.setString(2, password);
			ResultSet rs = getUserInfo.executeQuery();
			User userObj = new User();
			int i = 0;
			while (rs.next()) {
				userObj= constructUserObject(rs);
				i++;
			}
			if (i == 0) {
				throw new BaseException(new Exception(), "500",
						"Email and password is not correct");
			}
			return UUID.randomUUID();
		} catch (BaseException be) {
			throw be;
		} catch (Exception e) {
			throw new BaseException(e, "500", e.getMessage());
		}
	}
	
	
	private User constructUserObject(ResultSet rs){
		User userObj= new User();
		try {
			userObj.setUserId(Integer.parseInt(rs.getString("userid")));
			userObj.setEmail(rs.getString("email"));
			userObj.setFbuId(rs.getString("fbuid"));
			userObj.setTtrId(rs.getString("ttrid"));
			userObj.setLnkId(rs.getString("lnkid"));
			userObj.setUserName(rs.getString("username"));
			userObj.setFirstName(rs.getString("fname"));
			userObj.setLastName(rs.getString("lname"));
			userObj.setImagePath(rs.getString("profile image path"));
			userObj.setEmailVarification(rs.getString("email varification"));
			userObj.setDob(rs.getString("DOB"));
			userObj.setGender(rs.getString("gender"));
			userObj.setPassword(rs.getString("pwd"));
			userObj.setIsAdmin(Boolean.valueOf(rs.getString("Isadmin")));
			
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return userObj;
	}

}
